from typing import Optional, Dict, Any, List
from contextvars import ContextVar


class UserContext:
    """
    简化的用户上下文对象，保存当前请求的基本用户信息。

    字段来源优先为令牌载荷：
    - uid: 用户ID（来自令牌中的 `uid`）
    - username: 用户名（来自令牌中的 `sub`）
    - roles: 角色列表（来自令牌中的 `roles`）
    - role_ids: 角色ID列表（来自令牌中的 `role_ids`）
    - department: 用户所属部门编码
    - person_id: 人员ID，用于关联其他表
    - dept_codes: 用户可访问的部门编码列表（包含子部门）
    - raw: 原始载荷，供需要更多字段时直接访问
    """

    def __init__(
        self,
        uid: Optional[int] = None,
        name: Optional[str] = None,
        username: Optional[str] = None,
        department: Optional[str] = None,
        roles: Optional[List[Any]] = None,
        role_ids: Optional[List[int]] = None,
        raw: Optional[Dict[str, Any]] = None,
        person_id: Optional[int] = None,
        dept_codes: Optional[List[str]] = None,
    ) -> None:
        self.uid = uid
        self.username = username
        self.name = name
        self.department = department    
        self.roles = roles or []
        self.role_ids = role_ids or []
        self.raw = raw or {}
        self.person_id = person_id   # 人员ID，用于关联其他表
        self.dept_codes = dept_codes or []  # 用户可访问的部门编码列表

    @property
    def is_authenticated(self) -> bool:
        return self.uid is not None or self.username is not None

    def has_role(self, role: Any) -> bool:
        """检查是否拥有指定角色"""
        try:
            return role in (self.roles or [])
        except Exception:
            return False



# 每个请求独立的上下文变量
_user_ctx: ContextVar[Optional[UserContext]] = ContextVar("user_context", default=None)


def set_user_context_from_payload(payload: Dict[str, Any]) -> UserContext:
    """根据令牌载荷设置用户上下文，并返回该上下文对象。"""
    ctx = UserContext(
        name=payload.get("name"),
        uid=payload.get("uid"),
        username=payload.get("sub"),
        department=payload.get("department"),
        roles=payload.get("roles") or [],
        role_ids=payload.get("role_ids") or [],
        person_id=payload.get("person_id"),
        dept_codes=payload.get("dept_codes") or [],  # 从JWT中获取部门列表
        raw=payload,
    )
    _user_ctx.set(ctx)
    return ctx


def get_user_context() -> UserContext:
    """获取当前请求的用户上下文；若未设置则返回空上下文对象。"""
    ctx = _user_ctx.get()
    if ctx is None:
        ctx = UserContext()
        _user_ctx.set(ctx)
    return ctx


def clear_user_context() -> None:
    """清理当前请求的用户上下文。"""
    _user_ctx.set(None)